/**
Company: Sarkar software technologys
WebSite: http://www.sarkar.cn
Author: yeganaaa
Date : 11/3/17
Time: 5:20 PM
 */

package Cn.Sarkar.SimplePipeLineServer.Core.Features.Route

import Cn.Sarkar.Pipeline.Core.Info.FeatureInfo
import Cn.Sarkar.Pipeline.Core.PipeLineContext
import Cn.Sarkar.Pipeline.Core.PipeLineFeature
import Cn.Sarkar.Pipeline.Core.PipeLineFeatureMetaData
import Cn.Sarkar.SimplePipeLineServer.Core.Entities.SubjectParameter
import Cn.Sarkar.SimplePipeLineServer.Core.PipeLines.PipeLineInfraStructure

abstract class Router<TSubject, TFeatureProvider>(var routeSelector: IRouteSelector<SubjectParameter<TSubject>, TFeatureProvider>) : PipeLineFeature<SubjectParameter<TSubject>, TFeatureProvider>() {
    open override val getMetaData: PipeLineFeatureMetaData = PipeLineFeatureMetaData(PipeLineInfraStructure.routing, "Application.CoreFeature.Router:${routeSelector}")
    open var throwHandledError = true
    open override val info: FeatureInfo
        get() {
            return FeatureInfo(
                    "Router ${routeSelector}",
                    "سىستېما تەمىنلىگەن يول باشلىغۇچ، يول باشلىغۇچ تاللىغۇچى: ${routeSelector}",
                    "Sarkar Software Technologys",
                    "yeganaaa",
                    1,
                    "v0.1"
            )
        }

    open override fun PipeLineContext<SubjectParameter<TSubject>, TFeatureProvider>.onExecute(subject: SubjectParameter<TSubject>) {
        if (subject.isHandled and throwHandledError) throw Exception("يول باشلىغۇچ تەكرارلاندى، يول باشلىغۇچ تاللىغۇچى ئىپادىسىدە ياكى باشقا بۆلەكلەردە خاتالىق كۆرۈلگەن بولىشى مۇمكىن، تەكشۈرۈپ بىقىڭ!")
        routeSelector.apply {
            if (select()){
                action(subject)
                subject.isHandled = true
            }
        }
    }
    abstract fun PipeLineContext<SubjectParameter<TSubject>, TFeatureProvider>.action(subject: SubjectParameter<TSubject>)
}

fun <TSubject, TFeatureProvider>PipeLineContext<SubjectParameter<TSubject>, TFeatureProvider>.proceedWith(data: TSubject) : TSubject{
    return proceedWith(subject!!.apply { this.data = data }).data
}